package javaapplication8.Make;

// $Source: /h/u1/szamosi/repo/b07/examples/remake/Make.java,v $
// $Date: 2007/06/24 00:25:13 $
// $Revision: 1.1.1.1 $

import java.util.List;
import java.util.Iterator;
import java.io.FileReader;
import java.io.InputStreamReader;
import java.io.BufferedReader;
import java.io.FileNotFoundException;

class Make {

    // Main driver
    public static void main(String[] args) {
        // Create input stream
        BufferedReader input = null;
        int firstOutOfDate = 0;
        if ((args.length > 0) && args[0].equals("-f")) {
            try {
                input = new BufferedReader(new FileReader(args[1]));
            }
            catch (FileNotFoundException e) {
                System.err.println("Unable to find file: " + args[1]);
                System.exit(1);
            }
            firstOutOfDate = 2;
        }
        else {
            input = new BufferedReader(new InputStreamReader(System.in));
        }
        
        // Read rules
        ParseStateMachine parser = new ParseStateMachine();
        List rules = parser.parse(input);
        
        // Create dependency graph
        DirectedGraph graph = rulesToGraph(rules);
        
        // Create rules for pre-requisites that aren't targets
        fillInGraph(graph);
        
        // Mark specified targets as out-of-date
        for (int i=firstOutOfDate; i<args.length; ++i) {
            MakeRule rule = (MakeRule)graph.getData(args[i]);
            rule.setChanged(true);
        }
        
        // Update
        Iterator in = graph.getNodes().iterator();
        while (in.hasNext()) {
            update(graph, in.next());
        }
    }

    // Convert a list of rules to a directed graph
    public static DirectedGraph rulesToGraph(List ruleList) {
        DirectedGraph graph = new DirectedGraph();
        Iterator ir = ruleList.iterator();
        while (ir.hasNext()) {
            Rule rule = (Rule)ir.next();
            String target = rule.getTarget();
            graph.addNode(target);
            graph.setData(target, rule);
            Iterator ia = rule.getPrereqIter();
            while (ia.hasNext()) {
                graph.addArc(target, ia.next());
            }
        }
        return graph;
    }

    // Fill in the graph by adding empty data for nodes that were
    // referenced but didn't have explicit rules
    public static void fillInGraph(DirectedGraph graph) {
        Iterator in = graph.getNodes().iterator();
        while (in.hasNext()) {
            Object node = in.next();
            if (graph.getData(node) == null) {
                Rule rule = new MakeRule();
                rule.setTarget((String)node);
                graph.setData(node, rule);
            }
        }
    }

    // Update the nodes in the graph, respecting dependencies
    public static boolean update(DirectedGraph graph, Object node) {

        MakeRule rule = (MakeRule)graph.getData(node);
        
        // Check pre-requisites first
        boolean prereqChanged = false;
        Iterator ia = graph.getArcs(node).iterator();
        while (ia.hasNext()) {
            Object prereq = ia.next();
            if (update(graph, prereq)) {
                prereqChanged = true;
            }
        }
        
        // Explicit change, or pre-requisites have changed?
        if (prereqChanged || rule.isChanged()) {
            rule.execute();
            return true;
        }
        
        // No reason to update parent
        return false;
    }
}
